package com.jasperframework.boot.common.utils;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
  * <p>  </p>
  *
  * @site https://miliqkdoc.motopa.cn/
  * @author daizhao
  * @date 2022/12/12 12:12
  */
public class ProcessBuilderUtils {

	private static final Logger logger = LoggerFactory.getLogger(ProcessBuilderUtils.class);

	public static int runCommand(String ...command){
		ProcessBuilder pb = new ProcessBuilder(command);
		Process process;
		int runningStatus = 0;//runningStatus：运行状态，0标识正常。
		try {
			process = pb.start();
			runningStatus = process.waitFor(); //操作系统错误代码128：Key被撤销
			if (runningStatus == 0 || runningStatus == 128) {
				logger.info("command执行成功={}", command);
			} else {
				logger.info("command执行失败={}", command);
			}
			return runningStatus;
		} catch (IOException e) {
			logger.error("command={}", e.getMessage());
		} catch (InterruptedException e) {
			logger.error("command={}", e.getMessage());
		}
		return -1;
	}

	/**
	 *
	 * @param RUNNING_SHELL_DIR  要运行的脚本所在的目录； 当然你也可以把要运行的脚本写成全路径
	 * @param RUNNING_SHELL_FILE 要运行的脚本
	 * @param $param1, $param2, param3：可以在RUNNING_SHELL_FILE脚本中直接通过$1,$2,$3分别拿到的参数。
	 */
	public static List<String> runLinuxCommand(String RUNNING_SHELL_DIR, String RUNNING_SHELL_FILE, String $param1, String $param2){
		ProcessBuilder pb = new ProcessBuilder(RUNNING_SHELL_FILE, $param1, $param2);
		pb.directory(new File(RUNNING_SHELL_DIR));
		int runningStatus = 0;//runningStatus：运行状态，0标识正常。
		try {
			Process p = pb.start();
			List<String> lines = print(p);
			runningStatus = p.waitFor();
			if(runningStatus == 0 ){
				logger.info("RUN SUCCESS");
				return lines;
			}else{
				logger.info("RUN FAIL");
				return null;
			}
		} catch (IOException e) {
			logger.error("pb.start() exception=" + e.getMessage());
		} catch (InterruptedException e) {
			logger.error("p.waitFor() exception=" + e.getMessage());
		}
		return null;
	}

	public static List<String> runLinuxCommand(String RUNNING_SHELL_FILE, String RUNNING_SHELL_DIR){
		ProcessBuilder pb = new ProcessBuilder();
		if(StringUtils.isNotEmpty(RUNNING_SHELL_DIR)){
			pb.directory(new File(RUNNING_SHELL_DIR));
		}
		pb.command(RUNNING_SHELL_FILE);
		int runningStatus = 0;//runningStatus：运行状态，0标识正常。
		try {
			Process p = pb.start();
			List<String> lines = print(p);
			runningStatus = p.waitFor();
			if(runningStatus == 0 ){
				logger.info("RUN SUCCESS");
				return lines;
			}else{
				logger.info("RUN FAIL");
				return null;
			}
		} catch (IOException e) {
			logger.error("pb.start() exception=" + e.getMessage());
		} catch (InterruptedException e) {
			logger.error("p.waitFor() exception=" + e.getMessage());
		}
		return null;

	}

	public static int runLinuxCommand(List<String> commands, String RUNNING_SHELL_DIR){
		ProcessBuilder pb = new ProcessBuilder();
		if(StringUtils.isNotEmpty(RUNNING_SHELL_DIR)){
			pb.directory(new File(RUNNING_SHELL_DIR));
		}
		pb.command(commands);
		int runningStatus = 0;//runningStatus：运行状态，0标识正常。
		try {
			Process p = pb.start();
			print(p);
			runningStatus = p.waitFor();
			if(runningStatus == 0 ){
				logger.info("RUN SUCCESS");
				return 1;
			}else{
				logger.info("RUN FAIL");
				return 0;
			}
		} catch (IOException e) {
			logger.error("pb.start() exception=" + e.getMessage());
		} catch (InterruptedException e) {
			logger.error("p.waitFor() exception=" + e.getMessage());
		}
		return 1;
	}

	public static Integer runWindowsCommand(List<String> command, String RUNNING_BAT_DIR){
		ProcessBuilder pb = new ProcessBuilder();
		if(StringUtils.isNotEmpty(RUNNING_BAT_DIR)){
			pb.directory(new File(RUNNING_BAT_DIR));
		}
		pb.command(command);
		int runningStatus = 0;//runningStatus：运行状态，0标识正常。
		try {
			Process p = pb.start();
			print(p);
			runningStatus = p.waitFor();
			if(runningStatus == 0 ){
				logger.info("RUN SUCCESS");
				return 1;
			}else{
				logger.info("RUN FAIL");
				return 0;
			}
		} catch (IOException e) {
			logger.error("pb.start() exception=" + e.getMessage());
		} catch (InterruptedException e) {
			logger.error("p.waitFor() exception=" + e.getMessage());
		}
		return null;

	}

	public static List<String> runWindowsCommand(String RUNNING_BAT_FILE, String RUNNING_BAT_DIR){
		ProcessBuilder pb = new ProcessBuilder();
		if(StringUtils.isNotEmpty(RUNNING_BAT_DIR)){
			pb.directory(new File(RUNNING_BAT_DIR));
		}
		pb.command(RUNNING_BAT_FILE);
		int runningStatus = 0;//runningStatus：运行状态，0标识正常。
		try {
			Process p = pb.start();
			print(p);
			runningStatus = p.waitFor();
			if(runningStatus == 0 ){
				logger.info("RUN SUCCESS");
			}else{
				logger.info("RUN FAIL");
			}
		} catch (IOException e) {
			logger.error("pb.start() exception=" + e.getMessage());
		} catch (InterruptedException e) {
			logger.error("p.waitFor() exception=" + e.getMessage());
		}
		return null;

	}

	/**
	 * 打印脚本缓存区的内容（print、echo的内容）
	 * 注意：要循环错误信息，否则会有死锁出现【如果内存较低就会死锁】用于防止缓存进程塞满缓存造成死锁
	 * @param p
	 * @return
	 */
	public static List<String> print(Process p){
		String line = null;
		List<String> lines = new ArrayList<String>();
        try {
        	BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream(), "gbk"));
        	BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream(), "gbk"));
        	while ((line = stdError.readLine()) != null) {
		        logger.info("stdError{}：" + line);
		    }
        	while ((line = stdInput.readLine()) != null) {
				lines.add(line);
				logger.info("stdInput{}：" + line);
			}
		} catch (IOException e) {
			logger.error("print"+e.getMessage());
		}

        return lines;
	}

	/**
	 * 打印脚本缓存区的内容（用于防止缓存进程塞满缓存造成死锁 注意：要循环错误信息，否则会有死锁出现【如果内存较低就会死锁】 ）
	 * @param p
	 * @return
	 */
	public static void printOfFFmpeg(Process p){
        byte[] b = new byte[1024];
        int readbytes = -1;
        try {
        	InputStream stdInput = p.getInputStream();
        	InputStream stdError = p.getErrorStream();
        	while ((readbytes = stdError.read(b)) != -1) {
		        logger.info("stdError{}：" + new String(b,0,readbytes));
		    }
			while ((readbytes = stdInput.read(b)) != -1) {
				logger.info("stdInput{}：" + new String(b,0,readbytes));
			}
		} catch (IOException e) {
			logger.error("print"+e.getMessage());
		}
	}

	/**
	 * 授权脚本方法
	 * @param RUNNING_SHELL_DIR   要运行的脚本所在的目录； 当然你也可以把要运行的脚本写成全路径
	 * @param RUNNING_SHELL_FILE  要运行的脚本
	 * @return
	 */
	public static int chmod(String RUNNING_SHELL_DIR, String RUNNING_SHELL_FILE){
		ProcessBuilder pb = new ProcessBuilder("/bin/chmod", "777", RUNNING_SHELL_FILE);
		pb.directory(new File(RUNNING_SHELL_DIR));
        Process process;
        int runningStatus = 0;//runningStatus：运行状态，0标识正常。
		try {
			process = pb.start();
			runningStatus = process.waitFor();
			return runningStatus;
		} catch (IOException e) {
			logger.error("chmod"+e.getMessage());
		}catch (InterruptedException e) {
			logger.error("chmod"+e.getMessage());
		}
		return -1;
	}

	public static void main(String[] args) {

		new Thread(){
			@Override
            public void run() {
				//runWindowsCommond("D:/iseupload/1.bat", null);
				//视频转换  mov转换mp4
				List<String> commands = new ArrayList<String>();
				commands.add("ffmpeg");
				commands.add("-i");
				commands.add("1.mov");//原视频
				commands.add("-vcodec");
				commands.add("libx264");
				commands.add("-profile:v");
				commands.add("baseline");

				commands.add("-vf");
				commands.add("scale=750:-1");//将输入的1920x1080缩小到960x540输出:如果540不写，写成-1，即scale=960:-1, 那也是可以的，ffmpeg会通知缩放滤镜在输出时保持原始的宽高比。

				commands.add("1.mp4");
				runWindowsCommand(commands, "D:/iseupload");

				//截视频录像
				List<String> commands2 = new ArrayList<String>();
				commands2.add("ffmpeg");
				commands2.add("-i");
				commands2.add("1.mp4");//原视频
				commands2.add("-y");  //覆盖
				commands2.add("-ss");//表示开始时间
				commands2.add("00:00:20");
				commands2.add("-t");//表示共要多少时间
				commands2.add("1");
				commands2.add("-r");
				commands2.add("1");
				commands2.add("-q:v");
				commands2.add("2");
				commands2.add("-f");
				commands2.add("image2");
		        //commands.add("screenshot%03d.jpg");//截图文件，自定义的，目前是当前目录的，动态生成多个截图“%03d”会根据时间自动生成001、002、003这种方式对应时间进度
		        //commands.add(new Date() + ".jpg");//截图文件，自定义的，目前是当前目录的
				commands2.add("screenshot.jpg");//截图文件，自定义的，目前是当前目录的
		        //runWindowsCommond(commands2, "D:/iseupload");

            }

		}.start();

	}

}
